package com.wisewin.pose.api.controller;

import com.wisewin.pose.api.controller.base.BaseController;
import com.wisewin.pose.config.dto.ResultDTO;
import com.wisewin.pose.entity.bo.QueryParamBO;
import com.wisewin.pose.entity.db.UserDO;
import com.wisewin.pose.service.OrgUserService;
import com.wisewin.pose.service.UserService;
import com.wisewin.pose.service.WechatService;
import com.wisewin.pose.util.wechatOffice.WXCheckUtils;
import com.wisewin.pose.util.wechatOffice.WechatRedisUtils;
import com.wisewin.pose.util.wechatOffice.WxMsgCrypt;
import com.wisewin.pose.util.wechatOffice.domain.AjaxResult;
import com.wisewin.pose.util.wechatOffice.string.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/wechat")
public class WechatController extends BaseController {
    final static Logger log = LoggerFactory.getLogger(WechatController.class);

    @Autowired
    private WXCheckUtils wxCheckUtils;
    @Autowired
    private WechatService wechatService;
    @Autowired
    private WxMsgCrypt wxMsgCrypt;
    @Autowired
    private WechatRedisUtils wechatRedisUtils;
    @Autowired
    private UserService userService;
    @Autowired
    private OrgUserService orgUserService;

    @ResponseBody
    @GetMapping("")
    public String wxOfficialTokenCheck(String signature, String timestamp, String nonce, String echostr) {
        log.info("开始校验此次消息是否来自微信服务器，param->signature:{},\ntimestamp:{},\nnonce:{},\nechostr:{}",
                signature, timestamp, nonce, echostr);
        if (wxCheckUtils.checkSignature(signature, timestamp, nonce)) {
            return echostr;
        }
        return "";
    }

    /**
     * 接收微信公众号的推送
     * 
     * @param resp
     * @return
     */
    @ResponseBody
    @PostMapping(value = "", produces = MediaType.APPLICATION_XML_VALUE)
    public String wxOfficialCallback(@RequestBody Map resp) {
        log.info("接收到推送消息：{}", resp);

        // String encrypt = resp.get("Encrypt").toString();
        // // 消息解密
        // // 解析xml
        // WXResponseXML wxResponseXML = XmlUtils.xmlToBean(xmlString,
        // WXResponseXML.class);
        // log.info("解析xml：{}", wxResponseXML.toString());
        // String event = wxResponseXML.getEvent();

        String encrypt = "";
        //
        String openid = "";
        String event = "";
        String qrId = "";// 二维码的标识

        // if (resp.containsKey("ToUserName")) {
        // return "success";
        // }

        // if (!resp.containsKey("Encrypt")) {
        // return "not encrypt";
        // }
        // Object encryptObj = resp.get("Encrypt");
        // if (encryptObj == null) {
        // return "no encrypt data";
        // }
        // encrypt = wxMsgCrypt.decrypt(encryptObj.toString());
        // WXResponseXML wxResponseXML = XmlUtils.xmlToBean(encrypt,
        // WXResponseXML.class);
        // event = wxResponseXML.getEvent();
        // openid = wxResponseXML.getFromUserName();

        Object eventObj = resp.get("Event");
        if (null != eventObj) {
            event = eventObj.toString();
        }
        if (event == null) {
            return "unknow event";
        }

        Object fromUserName = resp.get("FromUserName");
        if (null != fromUserName) {
            openid = fromUserName.toString();
        }

        switch (event) {
            case "subscribe": {
                log.info("关注事件，用户：{}", openid);
                Object eventKey = resp.get("EventKey");
                if (null != eventKey && !StringUtils.isEmpty(eventKey.toString())) {
                    qrId = eventKey.toString().substring(8);
                }
                userService.addUser(openid);
                break;
            }
            case "SCAN": {
                log.info("扫描事件，用户：{}", openid);
                Object eventKey = resp.get("EventKey");
                if (null != eventKey) {
                    qrId = eventKey.toString();
                }
                break;
            }
            case "unsubscribe":
                log.info("取消关注，用户：{}", openid);
                break;
        }
        log.info("qrId:{}", qrId);
        // 登录成功，更新redis，把openid存入
        if (StringUtils.isNotEmpty(qrId)) {
            log.info("存入redis：{}", openid);
            wechatRedisUtils.scanQr(qrId, openid);
            // 获取机构ID
            Integer orgId = qrId.split("@@@").length == 1 ? 2 : Integer.parseInt(qrId.split("@@@")[1].toString());
            // 创建用户
            orgUserService.insertOrIgnore(openid, orgId);
            return "success";
        }
        return "success";
    }

    /**
     * 用户点击“微信登录”后调用，返回二维码地址和生成的uuid
     * 
     * @return
     */
    @ResponseBody
    @GetMapping("/qrcode/{orgId}")
    public AjaxResult qrcode(@PathVariable("orgId") String orgId) {
        log.info("qrcode方法获取orgId: {}", orgId);
        // 处理机构id
        orgId = StringUtils.isEmpty(orgId) ? "1" : orgId;
        // 生成二维码的唯一标识，用于公众号推送过来时识别
        String qrId = UUID.randomUUID().toString().replace("-", "") + "@@@" + orgId;
        String qrUrl = wechatService.getQRUrl(qrId);
        // 把这个二维码标识存到redis里，3分钟有效，状态为wait等待扫描
        wechatRedisUtils.saveQrId(qrId);
        HashMap<String, String> map = new HashMap<>();
        map.put("id", qrId);// 把二维码标识返回页面，页面需要不断轮询查询该二维码有没有被扫描
        map.put("url", qrUrl);
        return new AjaxResult().put("data", map);
    }

    /**
     * 展示二维码后，页面需要轮询调用此请求，判定用户是否扫描并关注
     * 
     * @param qrId
     * @return
     */
    @ResponseBody
    @GetMapping("/check/{qrId}")
    public AjaxResult login(@PathVariable("qrId") String qrId) {
        String openid = wechatRedisUtils.getOpenid(qrId);
        // 登录成功
        log.info("登录成功: {}", openid);
        if (openid != null) {// 登录或创建用户并登录
            return AjaxResult.success("success").put("openid", openid);
        }
        return AjaxResult.warn("继续等待");
    }

    /**
     * 通过code进行登录时调用，一般用于公众号菜单点击后静默登录
     * 使用方式：公众号搞一个菜单，点击后打开链接：
     * https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxx&redirect_uri=https%3a%2f%2fyuming.com/wechat/login&response_type=code
     * &scope=snsapi_base&state=STATE#wechat_redirect
     * 替换appid和域名后即可实现免登录
     * 
     * @param code
     * @return
     */
    @GetMapping("/loginAuth")
    public ResultDTO codelogin(String code) {
        log.info("根据code进行登录：{}", code);
        ResultDTO resultDTO = userService.getAuthUserInfo(code);
        if ("1".equals(resultDTO.getCode())) {
            return resultDTO;
        }
        UserDO userDO = (UserDO) resultDTO.getData();
        String sessionId = super.setLoginUser(userDO);
        userDO.setSessionId(sessionId);
        resultDTO.setData(userDO);
        return resultDTO;
    }

    @GetMapping("/updateAuth")
    public ResultDTO codeUpdateInfo(@ModelAttribute QueryParamBO param) {
        log.info("根据code进行登录：{}", param.getCode());
        ResultDTO resultDTO = userService.updateAuthUserInfo(param);
        if ("1".equals(resultDTO.getCode())) {
            return resultDTO;
        }
        UserDO userDO = (UserDO) resultDTO.getData();
        String sessionId = super.setLoginUser(userDO);
        userDO.setSessionId(sessionId);
        resultDTO.setData(userDO);
        return resultDTO;
    }

    @GetMapping("/checkInfo")
    public ResultDTO getInfoWithCode(@ModelAttribute QueryParamBO param) {
        log.info("根据code进行登录：{}", param.getCode());
        ResultDTO resultDTO = userService.checkUserInfo(param);
        if ("1".equals(resultDTO.getCode()) || "0000001".equals(resultDTO.getCode())) {
            return resultDTO;
        }
        UserDO userDO = (UserDO) resultDTO.getData();
        String sessionId = super.setLoginUser(userDO);
        userDO.setSessionId(sessionId);
        resultDTO.setData(userDO);
        return resultDTO;
    }
}
